﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using RQX.Common.Web.Authority;
using RQX.Common.Web.Core.PDF;
using RQX.Common.Web.Logger;
using RQX.Common.Web.Logger.InterfaceLogger;
using RQX.Common.Web.Web.Container;
using System;
using System.Linq;
using System.Web.Http.Results;

namespace RQX.Common.Web.Web.Filter
{
    /// <summary>
    /// Api action统一处理过滤器
    /// 处理正常返回值 {code:200,body:{}}
    /// </summary>
    public class ApiResponseFilterAttribute : ActionFilterAttribute, IIoCManager
    {
        private readonly InterfaceLogService _interfaceLogService;
        public ApiResponseFilterAttribute(InterfaceLogService interfaceLogService)
        {
            _interfaceLogService = interfaceLogService;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //接口日志初始化数据获取
            LoggerFilter.InterfaceLogInit(context);
            //进行访问合法性验证
            RequestValid(context);
            //模型验证
            ModelValid(context);
            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 处理正常返回的结果对象，进行统一json格式包装
        /// 异常只能交由ExceptionFilterAttribute 去处理 
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Result != null)
            {
                IActionResult newresult;
                if (context.Result is ObjectResult result)
                {
                    if (result.Value is PDFResult pdfResult)
                    {
                        newresult = new FileContentResult(pdfResult.buffer, "application/pdf");
                    }
                    else if (result.Value is ApiResponseMessage apiResponseMessage)
                    {
                        newresult = new JsonResult(apiResponseMessage.ToApiResponse());
                    }
                    else
                    {
                        newresult = new JsonResult(new ApiResponse(200, result.Value));
                    }
                }
                else if (context.Result is EmptyResult)
                {
                    newresult = new JsonResult(new ApiResponse(200));
                }
                else
                {
                    throw new Exception($"未经处理的Result类型：{ context.Result.GetType().Name}");
                }
                context.Result = newresult;
                LoggerFilter.InterfaceLogSuccessed(_interfaceLogService, newresult);
            }
            base.OnActionExecuted(context);
        }

        #region 内部实现
        /// <summary>
        /// 访问合法性验证
        /// </summary>
        /// <param name="context"></param>
        private void RequestValid(ActionExecutingContext context)
        {
            //获取nologin标签
            var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            //controller
            var controllerNoLoginList = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(typeof(NoLoginAttribute), false);
            if (controllerNoLoginList.Length == 0)//controller没有nologin标签
            {
                //action
                var actionNoLoginList = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(NoLoginAttribute), false);
                //没有标签则需要验证token
                if (actionNoLoginList.Length == 0)
                {
                    TokenValid(context);
                }
            }
        }

        /// <summary>
        /// Token验证
        /// </summary>
        /// <param name="context"></param>
        private void TokenValid(ActionExecutingContext context)
        {
            if (context.HttpContext.Request.Headers.ContainsKey("token"))
            {
                //验证token
                if (!LoginUser.CheckToken(context.HttpContext.Request.Headers["token"]))
                {
                    throw new ApolloException(ApolloExceptionType.登录已过期);
                }
            }
            else
            {
                throw new ApolloException(ApolloExceptionType.未登录);
            }
        }

        /// <summary>
        /// 模型验证
        /// </summary>
        /// <param name="context"></param>
        private void ModelValid(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                throw new ApolloException(ApolloExceptionType.参数验证失败, context.ModelState.Values.First(p => p.Errors.Count > 0).Errors[0].ErrorMessage);
            }
        }

        #endregion
    }
}
